# backend/app/api/api_gRPC.py

"""
gRPC 服务实现文件
定义和实现 VideoService 服务，用于视频流传输。
"""

from concurrent import futures  # 引入 futures 用于创建线程池
import grpc  # 引入 grpc 库
import asyncio  # 引入 asyncio 用于异步操作
import os
from pathlib import Path  # 引入 Path 用于路径操作

# 导入生成的 gRPC 类和服务基类
from app.api.generated import service_pb2, service_pb2_grpc
from app.db.db_file import get_video_path
from app.db.db_resources import get_resources
from app.utils.logger import get_logger  # 导入自定义日志记录器

logger = get_logger()  # 获取日志记录器实例

class VideoServiceServicer(service_pb2_grpc.VideoServiceServicer):
    """
    VideoServiceServicer 类实现了 VideoService 服务。
    提供视频流传输的功能。
    """
    
    async def StreamVideo(self, request, context):
        """
        处理视频流请求。
        
        参数:
            request (VideoRequest): 包含 video_id 的请求消息。
            context: gRPC 上下文对象，用于设置响应状态和元数据。
        
        返回:
            VideoResponse: 包含视频内容的响应消息（分段传输）。
        """
        video_id = request.video_id  # 获取请求中的视频ID
        logger.info(f"收到视频请求：{video_id}")  # 记录收到的视频请求
        video_path = get_video_path(video_id)  # 获取视频文件路径
        if not video_path or not video_path.exists():
            # 如果视频文件不存在，设置响应状态为 404 并返回空响应
            context.set_details('视频未找到')
            context.set_code(grpc.StatusCode.NOT_FOUND)
            return service_pb2.VideoResponse()
        
        CHUNK_SIZE = 1024 * 1024  # 定义每个视频块的大小为1MB
        try:
            with open(video_path, 'rb') as f:
                while True:
                    chunk = f.read(CHUNK_SIZE)  # 读取视频块
                    if not chunk:
                        break  # 如果没有更多数据，退出循环
                    yield service_pb2.VideoResponse(video_content=chunk)  # 发送视频块
        except Exception as e:
            # 如果发生异常，记录错误并设置响应状态为内部服务器错误
            logger.error(f"视频流传输错误：{e}")
            context.set_details('视频流传输错误')
            context.set_code(grpc.StatusCode.INTERNAL)
            return service_pb2.VideoResponse()
        
    async def GetResource(self, request, context):
        """
        处理获取资源数据的请求。
        
        参数:
            request (ResourceRequest): 包含 resource_id 的请求消息。
            context: gRPC 上下文对象，用于设置响应状态和元数据。
        
        返回:
            ResourceResponse: 包含资源数据的响应消息。
        """
        resource_id = request.resource_id  # 获取请求中的资源ID
        logger.info(f"收到获取资源请求：{resource_id}")  # 记录收到的资源请求
        resource = get_resources(resource_id)  # 获取资源数据
        if not resource:
            # 如果资源不存在，设置响应状态为 404 并返回空响应
            context.set_details('资源未找到')
            context.set_code(grpc.StatusCode.NOT_FOUND)
            return service_pb2.ResourceResponse()
        
        try:
            # 构建并返回资源响应
            response = service_pb2.ResourceResponse(
                resource_id=resource.id,
                name=resource.name,
                data=resource.data  # 根据实际情况调整字段
            )
            return response
        except Exception as e:
            # 如果发生异常，记录错误并设置响应状态为内部服务器错误
            logger.error(f"获取资源数据错误：{e}")
            context.set_details('获取资源数据错误')
            context.set_code(grpc.StatusCode.INTERNAL)
            return service_pb2.ResourceResponse()
async def serve_grpc(server_address='[::]:50051'):
    """
    启动 gRPC 服务器并监听指定地址。
    
    参数:
        server_address (str): 服务器监听地址，默认为 '[::]:50051'。
    """
    # 创建一个基于线程池的 gRPC 服务器
    server = grpc.aio.server(futures.ThreadPoolExecutor(max_workers=10))
    # 将 VideoServiceServicer 添加到服务器
    service_pb2_grpc.add_VideoServiceServicer_to_server(VideoServiceServicer(), server)
    # 添加服务监听的地址
    server.add_insecure_port(server_address)
    logger.info(f"gRPC 服务器启动在 {server_address}")  # 记录服务器启动信息
    await server.start()  # 启动服务器
    await server.wait_for_termination()  # 等待服务器终止

def start_grpc_server():
    """
    启动 gRPC 服务器的同步方法。
    """
    asyncio.run(serve_grpc())  # 运行异步的 serve_grpc 函数

if __name__ == '__main__':
    start_grpc_server()  # 如果该文件被直接运行，则启动 gRPC 服务器